package upload

import (
	"context"
	"mini-upload/internal/dao"
	"mini-upload/internal/model/entity"
	"mini-upload/utility/code"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"mini-upload/api/upload/v1"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/marcellowy/go-common/gogf/vconfig"
	"github.com/marcellowy/go-common/gogf/vlog"
	"github.com/marcellowy/go-common/vhash"
)

func checkExt(ctx context.Context, filename string) bool {
	var ext = strings.ToLower(path.Ext(filename))
	if ext[:1] == "." {
		ext = ext[1:]
	}
	suffix := vconfig.Get("upload.allowExts", []string{}).Strings()
	for _, v := range suffix {
		if ext == v {
			return true
		}
	}
	vlog.Warningf(ctx, "%s not allowed", ext)
	return false
}

func (c *ControllerV1) MiniUpload(ctx context.Context, req *v1.MiniUploadReq) (res *v1.MiniUploadRes, err error) {
	savePath := vconfig.Get("upload.savePath").String()
	allowExts := vconfig.Get("upload.allowExts").Strings()
	if savePath == "" || len(allowExts) == 0 {
		vlog.Warning(ctx, "upload savePath or allowExts is empty")
		err = code.ErrorParam
		return
	}
	if req.DirectoryName == "" {
		req.DirectoryName = "default"
	}
	res = &v1.MiniUploadRes{}
	uploadFile := g.RequestFromCtx(ctx).GetUploadFile("file")
	if uploadFile == nil {
		err = code.ErrorNoFileUploaded
		vlog.Warning(ctx, err)
		return
	}
	if !checkExt(ctx, uploadFile.Filename) {
		err = code.ErrorDenyFileExt
		vlog.Warning(ctx, err)
		return
	}
	now := time.Now().Format("200601")
	dir := path.Join(savePath, req.DirectoryName, now)
	if _, err = os.Stat(dir); err != nil {
		if !os.IsNotExist(err) {
			vlog.Warning(ctx, err)
			err = code.ErrorSystem
			return
		}
		if err = os.MkdirAll(dir, os.ModePerm); err != nil {
			vlog.Warning(ctx, err, dir)
			err = code.ErrorSystem
			return
		}
	}
	var name string
	if name, err = uploadFile.Save(dir, true); err != nil {
		vlog.Warning(ctx, err, dir)
		err = code.ErrorSystem
		return
	}
	savefile := filepath.Join(dir, name)
	res.Md5, err = vhash.Md5File(savefile)
	if err != nil {
		vlog.Warning(ctx, err, savefile)
		return
	}
	res.Sha1, err = vhash.Sha1File(savefile)
	if err != nil {
		vlog.Warning(ctx, err, savefile)
		return
	}
	accessPath := filepath.Join(req.DirectoryName, now, name)
	attachment := entity.Attachment{
		Path:     accessPath,
		SavePath: filepath.Join(dir, name),
		Md5:      res.Md5,
		Sha1:     res.Sha1,
	}
	err = dao.NewAttachment().Create(ctx, &attachment)
	if err != nil {
		vlog.Warning(ctx, err)
		err = code.ErrorSystem
		return
	}
	res.Path = accessPath // 访问路径,域名由业务自己决定比较好
	res.Id = strconv.FormatInt(attachment.AttachmentId, 10)
	return
}
